package game

import (
	"bytes"
	"errors"
	"fmt"
	"game_go/base/database/mysql"
	"game_go/base/util"
	"game_go/dao"
	"log"
	"os"
	"sync"
)

var mLock sync.Mutex

func QueryGameList(name, acc, token, proc string, used, lock, done, cp, sz int64) (map[string]interface{}, error) {
	mResult := util.EmptyMap()
	mResult["list"] = util.EmptyArray()
	mResult["count"] = 0
	sqlBuffer := bytes.NewBufferString("SELECT id,game_name as name,account as acc,pwd,gold,token,progress_id as proc, is_used as used,is_down as locked,is_export as done FROM game_info where 1=1")

	sqlCount := bytes.NewBufferString("SELECT COUNT(id) as counts FROM game_info where 1=1")
	var values []interface{}
	parameters := bytes.NewBufferString("")
	if name != "" {
		parameters.WriteString(" and game_name like ?")
		values = append(values, "%"+name+"%")
	}

	if acc != "" {
		parameters.WriteString(" and account like ?")
		values = append(values, "%"+acc+"%")
	}

	if token != "" {
		parameters.WriteString(" and token=?")
		values = append(values, token)
	}
	if proc != "" {
		parameters.WriteString(" and progress_id=?")
		values = append(values, proc)
	}

	if used != -1 {
		parameters.WriteString(" and is_used=?")
		values = append(values, used)
	}
	if lock != -1 {
		parameters.WriteString(" and is_down=?")
		values = append(values, lock)
	}
	if done != -1 {
		parameters.WriteString(" and is_export=?")
		values = append(values, done)
	}
	sqlCount.WriteString(parameters.String())
	mCount, err := dao.Database.QueryForMap(sqlCount.String(), values...)
	if err != nil {
		log.Println(err)
		return mResult, err
	}

	sqlBuffer.WriteString(parameters.String())
	sqlBuffer.WriteString(" limit ?,?")
	values = append(values, cp, sz)
	log.Println(sqlBuffer.String(), values)
	mData, err := dao.Database.QueryForMapSlice(sqlBuffer.String(), values...)
	if err != nil {
		log.Println(err)
		return mResult, err
	}
	if mData != nil && mCount != nil {
		mResult["list"] = mData
		mResult["count"] = mCount["counts"]
	}
	return mResult, nil
}

func InsertGameInfo(gameInfos []map[string]interface{}) error {
	log.Println("gameInfos:", gameInfos)
	var sFails []string
	sql := "INSERT INTO game_info (game_name,account,pwd,progress_id) VALUES (?,?,?,?)"
	for _, value := range gameInfos {
		if value["name"] != nil && value["accont"] != nil && value["pwd"] != nil && value["proc"] != nil {
			name := value["name"].(string)
			account := value["accont"].(string)
			pwd := value["pwd"].(string)
			proc := value["proc"].(string)
			log.Println("value:", name, account, pwd)
			_, err := dao.Database.Insert(sql, name, account, pwd, proc)
			if err != nil {
				log.Println(err)
				//这里记录错误的条目
				sFail := fmt.Sprintf("%s %s %s %s\n", name, account, pwd, proc)
				sFails = append(sFails, sFail)
			}
		}
	}
	if len(sFails) != 0 {
		f, err := os.Create("fail.txt")
		if err != nil {
			log.Println(err)
		}
		for _, fail := range sFails {
			_, err = f.Write([]byte(fail))
			if err != nil {
				log.Println(err)
			}
		}
	}
	sql = "INSERT INTO game_log (content) VALUES (?)"
	content := fmt.Sprintf("insert into %d items ", len(gameInfos))
	_, err := dao.Database.Insert(sql, content)
	if err != nil {
		log.Println(err)
	}
	return nil
}

func InsertLog(tx *mysql.Tx, value string) (int64, error) {
	sql := "INSERT INTO game_log (content) VALUES (?)"
	return tx.Insert(sql, value)
}

func QueryIssued(name, proc string) (map[string]interface{}, error) {
	mLock.Lock()
	defer mLock.Unlock()
	mResult := make(map[string]interface{}, 0)
	tx, err := dao.Database.BeginTx()
	if err != nil {
		log.Println(err)
		return mResult, err
	}
	defer tx.Close()

	sql := "SELECT id,account as acc,pwd FROM game_info WHERE game_name=? and progress_id=? and is_used=0 and is_down=0 and is_export=0 limit 1"
	mData, err := tx.QueryForMap(sql, name, proc)
	log.Println("mData:", mData)
	if err != nil {
		log.Println(err)
		return mResult, err
	}
	if mData != nil {
		//
		sql = "UPDATE game_info SET is_down=1 WHERE id=?"
		nID, ok := mData["id"].(int64)
		if !ok {
			log.Println("id type error")
			tx.ErrorHappen()
			return mResult, errors.New("id type error")
		}
		_, err := tx.Update(sql, nID)
		if err != nil {
			log.Println(err)
			tx.ErrorHappen()
			return mResult, err
		}

		sCoutent := "update is_down 0 to 1"
		_, err = InsertLog(tx, sCoutent)
		if err != nil {
			log.Println(err)
			tx.ErrorHappen()
			return mResult, err
		}
		mResult = mData
	}
	return mResult, nil
}

func UpdateInfo(name, acc, token, proc string, gold int64) error {
	tx, err := dao.Database.BeginTx()
	if err != nil {
		log.Println(err)
		return err
	}
	defer tx.Close()
	sql := "SELECT progress_id FROM game_info WHERE game_name=? and account=? and is_export=0"
	mPro, err := tx.QueryForMap(sql, name, acc)
	if err != nil {
		log.Println(err)
		return err
	}

	if mPro != nil {
		sPro := mPro["progress_id"].(string)
		nUsed := 0
		if sPro == proc {
			//进程相同-已使用  进程不相同-未使用
			nUsed = 1
		}
		sql = "UPDATE game_info SET is_used=? WHERE game_name=? and account=? and is_export=0"
		_, err = tx.Update(sql, nUsed, name, acc)
		if err != nil {
			log.Println(err)
			tx.ErrorHappen()
			return err
		}
		sContent := fmt.Sprintf("update is_used to %d", nUsed)
		_, err = InsertLog(tx, sContent)
		if err != nil {
			log.Println(err)
			tx.ErrorHappen()
			return err
		}
	}

	sql = "UPDATE game_info SET gold=?,is_down=0,progress_id=?,token=? WHERE game_name=? and account=? and is_export=0"
	_, err = tx.Update(sql, gold, proc, token, name, acc)
	if err != nil {
		log.Println(err)
		tx.ErrorHappen()
		return err
	}
	sContent := fmt.Sprintf("update is_down to 0,gold to %d,progress_id to %s,token to %s", gold, proc, token)
	_, err = InsertLog(tx, sContent)
	if err != nil {
		log.Println(err)
		tx.ErrorHappen()
		return err
	}
	return nil
}

func Export(name, proc string) ([]map[string]interface{}, error) {
	mLock.Lock()
	defer mLock.Unlock()
	sqlBuffer := bytes.NewBufferString("SELECT game_name as name,account as acc,pwd,gold FROM game_info WHERE is_export=0")
	var values []interface{}
	if name != "" {
		values = append(values, "%"+name+"%")
		sqlBuffer.WriteString(" and name like ?")
	}

	if proc != "" {
		values = append(values, proc)
		sqlBuffer.WriteString(" and progress_id=?")
	}

	return dao.Database.QueryForMapSlice(sqlBuffer.String(), values...)
}

func UpdateExport(exports []map[string]interface{}) error {
	tx, err := dao.Database.BeginTx()
	if err != nil {
		log.Println(err)
		return err
	}
	defer tx.Close()
	nCount := int(0)
	sql := "UPDATE game_info SET is_export=1 WHERE game_name=? and account=? and is_export=0"
	for _, value := range exports {
		if value["name"] != nil {
			_, err := tx.Update(sql, value["name"].(string), value["acc"].(string))
			if err != nil {
				log.Println(err)
				nCount = nCount + 1
			}
		}
	}
	sContent := fmt.Sprintf("exports %d items", len(exports)-nCount)
	_, err = InsertLog(tx, sContent)
	if err != nil {
		log.Println(err)
		tx.ErrorHappen()
		return err
	}

	return nil
}

func QueryBy(name, acc, pwd, token, proc string, used, lock, done, cp, sz int64) ([]map[string]interface{}, error) {
	sqlBuffer := bytes.NewBufferString("SELECT game_name as name,account as acc,pwd,gold,token,progress_id as proc FROM game_info WHERE is_export=0")
	var values []interface{}
	if name != "" {
		sqlBuffer.WriteString(" and game_name=?")
		values = append(values, name)
	}
	if acc != "" {
		sqlBuffer.WriteString(" and account=?")
		values = append(values, acc)
	}
	if pwd != "" {
		sqlBuffer.WriteString(" and pwd=?")
		values = append(values, pwd)
	}
	if token != "" {
		sqlBuffer.WriteString(" and token=?")
		values = append(values, token)
	}
	if proc != "" {
		sqlBuffer.WriteString(" and progress_id=?")
		values = append(values, proc)
	}
	if used != -1 {
		sqlBuffer.WriteString(" and is_used=?")
		values = append(values, used)
	}
	if lock != -1 {
		sqlBuffer.WriteString(" and is_down=?")
		values = append(values, lock)
	}
	if done != -1 {
		sqlBuffer.WriteString(" and is_export=?")
		values = append(values, done)
	}

	sqlBuffer.WriteString(" limit ?,?")
	values = append(values, cp, sz)
	return dao.Database.QueryForMapSlice(sqlBuffer.String(), values...)
}

func UpdateUsed(name string) (int64, error) {
	sql := "UPDATE game_info SET is_used=0 WHERE is_export=0 and game_name=?"
	return dao.Database.Update(sql, name)
}

func InsertBasic(name, machine, region string, gold int64) (int64, error) {
	sql := "INSERT INTO game_basic (game_name,machine_name,region,gold) VALUES (?,?,?,?)"
	return dao.Database.Insert(sql, name, machine, region, gold)
}

func QueryBasic(name, machine, region string, cp, sz int64) ([]map[string]interface{}, error) {
	sqlBuffer := bytes.NewBufferString("SELECT game_name as name,machine_name,region,gold FROM game_basic WHERE 1=1")
	var values []interface{}
	if name != "" {
		sqlBuffer.WriteString(" and game_name=?")
		values = append(values, name)
	}
	if machine != "" {
		sqlBuffer.WriteString(" and machine_name=?")
		values = append(values, machine)
	}
	if region != "" {
		sqlBuffer.WriteString(" and region=?")
		values = append(values, region)
	}

	sqlBuffer.WriteString(" limit ?,?")
	values = append(values, cp, sz)
	return dao.Database.QueryForMapSlice(sqlBuffer.String(), values...)
}
